<template>
  <el-container>
    <p>
      <button id="btnChange" class="active">Change Model</button>
    </p>

    <div
      style="width:100%;text-align: center;"
      @mousemove="eventMouseMove"
      @mousedown="eventMouseDown"
      @mouseup="eventMouseUp"
      @mouseout="eventMouseOut"
      @contextmenu="changeModel"
      @wheel="eventWheel"
    >
      <canvas
        id="WebGLCanvas"
        ref="WebGLCanvas"
        width="680"
        height="940"
        style=""
      />
    </div>
  </el-container>
</template>
<style scoped>
  html, body {
    overflow: hidden;
    height: 100%;
  }

  body {
    margin: 0;
    padding: 0;
  }

  #WebGLCanvas {
    background-size: 150%;
    background-position: 50% 50%;
    background-image: url('https://lsh-server.oss-cn-beijing.aliyuncs.com/Haru/back_class_normal.png');
  }

  button {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 14px;
    color: #ffffff;
    padding: 10px 20px;
    -moz-border-radius: 30px;
    -webkit-border-radius: 30px;
    border-radius: 30px;
    -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5),
    inset 0 0 1px rgba(255,255,255,0.7);
    -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5),
    inset 0 0 1px rgba(255,255,255,0.7);
    box-shadow: 0 1px 3px rgba(0,0,0,0.5),
    inset 0 0 1px rgba(255,255,255,0.7);
    text-shadow: 0 -1px 0 rgba(0,0,0,0.4),
    0 1px 0 rgba(255,255,255,0.3);
  }

  button.active {
    background: linear-gradient(
      to bottom,
      #3498db,
      #2980b9);
    background: -moz-linear-gradient(
      top,
      #3498db 0%,
      #2980b9);
    background: -webkit-gradient(
      linear, left top, left bottom,
      from(#3498db),
      to(#2980b9));
    border: 1px solid #2980b9;
  }

  button.inactive {
    background: linear-gradient(
      to bottom,
      #e74c3c,
      #c0392b);
    background: -moz-linear-gradient(
      top,
      #e74c3c 0%,
      #c0392b);
    background: -webkit-gradient(
      linear, left top, left bottom,
      from(#e74c3c),
      to(#c0392b));
    border: 1px solid #c0392b;
  }
</style>
<script>
// framework
import { L2DMatrix44, L2DTargetPoint, L2DViewMatrix } from '../../assets/live2d/lib/framework/Live2DFramework'
// User's Script
import { MatrixStack } from '../../assets/live2d/lib/utils/MatrixStack.js'
import { LAppDefine } from '../../assets/live2d/lib/LAppDefine.js'
import { LAppLive2DManager } from '../../assets/live2d/lib/LAppLive2DManager.js'

export default {
  data: function() {
    return {
      platform: '',
      live2DMgr: {},
      isDrawStart: false,
      gl: null,
      canvas: null,
      dragMgr: null,
      viewMatrix: null,
      projMatrix: null,
      deviceToScreen: null,
      drag: false,
      oldLen: 0,
      lastMouseX: 0,
      lastMouseY: 0,
      isModelShown: false
    }
  },
  created: function() {
    // 主要是该方法
    this.$nextTick(function() {
      this.sampleApp1()
    })
  },
  methods: {
    sampleApp1: function() {
      this.platform = window.navigator.platform.toLowerCase()
      this.live2DMgr = new LAppLive2DManager()
      this.isDrawStart = false
      this.gl = null
      this.canvas = null
      this.dragMgr = null /* new L2DTargetPoint();*/
      this.viewMatrix = null /* new L2DViewMatrix();*/
      this.projMatrix = null /* new L2DMatrix44()*/
      this.deviceToScreen = null /* new L2DMatrix44();*/
      this.drag = false
      this.oldLen = 0
      this.lastMouseX = 0
      this.lastMouseY = 0
      this.isModelShown = false
      this.initL2dCanvas()
      this.init()
    },
    initL2dCanvas: function() {
      this.canvas = this.$refs.WebGLCanvas
      const self = this
      if (this.canvas.addEventListener && this.canvas) {
        this.canvas.addEventListener('touchstart', self.touchEvent(), false)
        this.canvas.addEventListener('touchend', self.touchEvent(), false)
        this.canvas.addEventListener('touchmove', self.touchEvent(), false)
      }

      const btnChangeModel = document.getElementById('btnChange')
      btnChangeModel.addEventListener('click', function() {
        self.changeModel()
      })
    },
    init: function() {
      const width = this.canvas.width
      const height = this.canvas.height

      this.dragMgr = new L2DTargetPoint()

      const ratio = height / width
      const left = LAppDefine.VIEW_LOGICAL_LEFT
      const right = LAppDefine.VIEW_LOGICAL_RIGHT
      const bottom = -ratio
      const top = ratio

      this.viewMatrix = new L2DViewMatrix()

      this.viewMatrix.setScreenRect(left, right, bottom, top)

      this.viewMatrix.setMaxScreenRect(LAppDefine.VIEW_LOGICAL_MAX_LEFT,
        LAppDefine.VIEW_LOGICAL_MAX_RIGHT,
        LAppDefine.VIEW_LOGICAL_MAX_BOTTOM,
        LAppDefine.VIEW_LOGICAL_MAX_TOP)

      this.viewMatrix.setMaxScale(LAppDefine.VIEW_MAX_SCALE)
      this.viewMatrix.setMinScale(LAppDefine.VIEW_MIN_SCALE)

      this.projMatrix = new L2DMatrix44()
      this.projMatrix.multScale(1, (width / height))

      this.deviceToScreen = new L2DMatrix44()
      this.deviceToScreen.multTranslate(-width / 2.0, -height / 2.0)
      this.deviceToScreen.multScale(2 / width, -2 / width)

      this.gl = this.getWebGLContext()
      if (!this.gl) {
        console.error('Failed to create WebGL context.')
        return
      }

      window.Live2D.setGL(this.gl)

      this.gl.clearColor(0.0, 0.0, 0.0, 0.0)

      this.changeModel()

      this.startDraw()
    },
    startDraw: function() {
      const self = this
      if (!this.isDrawStart) {
        this.isDrawStart = true;
        (function tick() {
          self.draw()

          const requestAnimationFrame =
            window.requestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.msRequestAnimationFrame

          requestAnimationFrame(tick, self.canvas)
        })()
      }
    },
    draw: function() {
      MatrixStack.reset()
      MatrixStack.loadIdentity()

      this.dragMgr.update()
      this.live2DMgr.setDrag(this.dragMgr.getX(), this.dragMgr.getY())

      this.gl.clear(this.gl.COLOR_BUFFER_BIT)

      MatrixStack.multMatrix(this.projMatrix.getArray())
      MatrixStack.multMatrix(this.viewMatrix.getArray())
      MatrixStack.push()

      for (let i = 0; i < this.live2DMgr.numModels(); i++) {
        const model = this.live2DMgr.getModel(i)

        if (model == null) return

        if (model.initialized && !model.updating) {
          model.update()
          model.draw(this.gl)

          if (!this.isModelShown && i === this.live2DMgr.numModels() - 1) {
            this.isModelShown = !this.isModelShown
            var btnChange = document.getElementById('btnChange')
            btnChange.textContent = 'Change Model'
            btnChange.removeAttribute('disabled')
            btnChange.setAttribute('class', 'active')
          }
        }
      }

      MatrixStack.pop()
    },
    changeModel: function() {
      const btnChange = document.getElementById('btnChange')
      btnChange.setAttribute('disabled', 'disabled')
      btnChange.setAttribute('class', 'inactive')
      btnChange.textContent = 'Now Loading...'
      this.isModelShown = false

      this.live2DMgr.reloadFlg = true
      this.live2DMgr.count++

      this.live2DMgr.changeModel(this.gl)
    },
    modelScaling: function(scale) {
      const isMaxScale = this.viewMatrix.isMaxScale()
      const isMinScale = this.viewMatrix.isMinScale()

      this.viewMatrix.adjustScale(0, 0, scale)

      if (!isMaxScale) {
        if (this.viewMatrix.isMaxScale()) {
          this.live2DMgr.maxScaleEvent()
        }
      }

      if (!isMinScale) {
        if (this.viewMatrix.isMinScale()) {
          this.live2DMgr.minScaleEvent()
        }
      }
    },
    modelTurnHead: function(event) {
      if ('button' in event && event.button !== 0) return
      this.drag = true

      const rect = event.target.getBoundingClientRect()

      if (!rect) { return }

      const sx = this.transformScreenX(event.clientX - rect.left)
      const sy = this.transformScreenY(event.clientY - rect.top)
      const vx = this.transformViewX(event.clientX - rect.left)
      const vy = this.transformViewY(event.clientY - rect.top)

      if (LAppDefine.DEBUG_MOUSE_LOG) { console.log('onMouseDown device( x:' + event.clientX + ' y:' + event.clientY + ' ) view( x:' + vx + ' y:' + vy + ')') }

      this.lastMouseX = sx
      this.lastMouseY = sy

      this.dragMgr.setPoint(vx, vy)

      this.live2DMgr.tapEvent(vx, vy)
    },
    followPointer: function(event) {
      var rect = event.target.getBoundingClientRect()

      var sx = this.transformScreenX(event.clientX - rect.left)
      var sy = this.transformScreenY(event.clientY - rect.top)
      var vx = this.transformViewX(event.clientX - rect.left)
      var vy = this.transformViewY(event.clientY - rect.top)

      if (LAppDefine.DEBUG_MOUSE_LOG) { console.log('onMouseMove device( x:' + event.clientX + ' y:' + event.clientY + ' ) view( x:' + vx + ' y:' + vy + ')') }

      if (this.drag) {
        this.lastMouseX = sx
        this.lastMouseY = sy

        this.dragMgr.setPoint(vx, vy)
      }
    },
    lookFront: function() {
      if (this.drag) {
        this.drag = false
      }

      this.dragMgr.setPoint(0, 0)
    },
    // 鼠标滚轮事件
    eventWheel: function() {
      const e = window.event || arguments[0]
      if (e.clientX < 0 || this.canvas.clientWidth < e.clientX ||
        e.clientY < 0 || this.canvas.clientHeight < e.clientY) {
        return
      }

      if (e.wheelDelta > 0) this.modelScaling(1.1)
      else this.modelScaling(0.9)
    },
    // 鼠标移动事件
    eventMouseMove: function(e) {
      this.followPointer(e)
    },
    // 鼠标左键松开事件
    eventMouseUp: function(e) {
      if ('button' in e && e.button !== 0) return
      this.lookFront(e)
    },
    // 鼠标左键按下去事件
    eventMouseDown: function(e) {
      if ('button' in e && e.button !== 0) return
      this.modelTurnHead(e)
    },
    // 指针离开元素
    eventMouseOut: function(e) {
      this.lookFront(e)
    },
    touchEvent: function(e) {
      e = window.event || arguments[0]
      if (e) {
        e.preventDefault()
        if (!e.touches) {
          return
        }
        const touch = e.touches[0]

        if (e.type === 'touchstart') {
          if (e.touches.length === 1) this.modelTurnHead(touch)
          // onClick(touch);
        } else if (e.type === 'touchmove') {
          this.followPointer(touch)

          if (e.touches.length === 2) {
            var touch1 = e.touches[0]
            var touch2 = e.touches[1]

            var len = Math.pow(touch1.pageX - touch2.pageX, 2) + Math.pow(touch1.pageY - touch2.pageY, 2)
            if (this.oldLen - len < 0) this.modelScaling(1.025)
            else this.modelScaling(0.975)

            this.oldLen = len
          }
        } else if (e.type === 'touchend') {
          this.lookFront()
        }
      }
    },
    transformViewX: function(deviceX) {
      const screenX = this.deviceToScreen.transformX(deviceX)
      return this.viewMatrix.invertTransformX(screenX)
    },
    transformViewY: function(deviceY) {
      const screenY = this.deviceToScreen.transformY(deviceY)
      return this.viewMatrix.invertTransformY(screenY)
    },
    transformScreenX: function(deviceX) {
      return this.deviceToScreen.transformX(deviceX)
    },
    transformScreenY: function(deviceY) {
      return this.deviceToScreen.transformY(deviceY)
    },
    getWebGLContext: function() {
      const NAMES = ['webgl', 'experimental-webgl', 'webkit-3d', 'moz-webgl']

      for (let i = 0; i < NAMES.length; i++) {
        try {
          const ctx = this.canvas.getContext(NAMES[i], { premultipliedAlpha: true })
          if (ctx) return ctx
        } catch (e) {
          console.log(e)
        }
      }
      return null
    }
  }
}
</script>
